package main

import (
	"fmt"
	"math"
	"os"
	"os/exec"
	"strings"
)

// HACK: rename version() -> app_version()
func app_version() {
	fmt.Printf("%s\n", Version)
	os.Exit(0)
}

func remove(path string) {
	go func() {
		cmd, ok := os.LookupEnv(CMD_walker_remove)
		if !ok {
			_ = os.RemoveAll(path)
		} else {
			_ = exec.Command(cmd, path).Run()
		}
	}()
}

func lookup(names []string, val string) string {
	for _, name := range names {
		val, ok := os.LookupEnv(name)
		if ok && val != "" {
			return val
		}
	}

	return val
}

func fileInfo(path string) os.FileInfo {
	fileInfo, err := os.Stat(path)
	if err != nil {
		panic(err)
	}

	return fileInfo
}

func leaveOnlyAscii(content []byte) string {
	var result []byte
	for _, b := range content {
		if b == '\t' {
			result = append(result, ' ', ' ', ' ', ' ')
		} else if b == '\r' {
			continue
		} else if (b >= 32 && b <= 127) || b == '\n' {
			result = append(result, b)
		}
	}

	return string(result)
}

// helper for wrap(...) func
type CallbackFunc func(name string, i, j int)

// todos: testing this func and document

func wrap(files []os.DirEntry, width, height int, callback CallbackFunc) ([][]string, int, int) {
	// if the directory is empty, return no names, rows, and columns
	if len(files) == 0 {
		return nil, 0, 0
	}
	// if it is possible to fit all files in one column on a third of the
	// screen, just use one column. Otherwise, let's squeeze listing in
	// half of screen
	columns := len(files) / max(1, height/3)
	if columns <= 0 {
		columns = 1
	}

	// max number of fils to display in one column is 10 or 4 columns in
	// total
	columnsEstimate := int(math.Ceil(float64(len(files)) / 10))
	columns = max(columns, min(columnsEstimate, 4))

	// for large lists, don't use more than 2 columns
	if len(files) > 100 {
		columns = 2
	}

	// fifteenth column is enough for eveyone
	if columns > 15 {
		columns = 15
	}
_LABEL_START:
	// let's try to fit everything in terminal width with this
	// many columns
	// if we are not able to do it, decrease column number and
	// goto `_LABEL_START`
	rows := int(math.Ceil(float64(len(files)) / float64(columns)))
	names := make([][]string, columns)

	n := 0

	for i := 0; i < columns; i++ {
		names[i] = make([]string, rows)
		// we will use this to determine max name size, and
		// pad names in column with spaces
		maxnNameSize := 0
		for j := 0; j < rows; j++ {
			if n >= len(files) {
				break // no more files to display
			}
			name := ""
			if showIcons {
				info, err := files[n].Info()
				if err == nil {
					icon := icons.getIcon(info)
					if icon != "" {
						name += icon + " "
					}
				}
			} // if

			name += files[n].Name()
			if callback != nil {
				callback(files[n].Name(), i, j)
			}

			if files[n].IsDir() {
				// dirs should have a slash at the end
				name += fileSeparator
			}

			n++ // next file

			if maxnNameSize < strlen(name) {
				maxnNameSize = strlen(name)
			}
			names[i][j] = name
		} // for loop

		// append spaces to make all names in one column of same size
		for j := 0; j < rows; j++ {
			names[i][j] += strings.Repeat(" ", maxnNameSize-strlen(names[i][j]))
		}
	} // for loop

	// let's verify was all columns have at least one file
	for i := 0; i < columns; i++ {
		if names[i] == nil {
			columns--
			goto _LABEL_START
		}

		columnHaveAtLeastOneFile := false
		for j := 0; j < rows; j++ {
			if names[i][j] != "" {
				columnHaveAtLeastOneFile = true
				break
			}
		}

		if !columnHaveAtLeastOneFile {
			columns--
			goto _LABEL_START
		}
	} // for loop

	for j := 0; j < rows; j++ {
		row := make([]string, columns)
		for i := 0; i < columns; i++ {
			row[i] = names[i][j]
		}

		if strlen(strings.Join(row, SEPARATOR)) > width && columns > 1 {
			// yep, no luck, let's decrease number of columns and try
			// one more time
			columns--
			goto _LABEL_START
		}
	} // for loop

	return names, rows, columns
}
